﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace Sakura.Media.AviSynth.Native
{
	/// <summary>
	/// 封装本地方法的辅助类型。
	/// </summary>
	internal static class NativeMethods
	{
		/// <summary>
		/// 提供本机方法的动态链接库名称。该字段为常量。
		/// </summary>
		public const string DllName = "AviSynth.dll";

		/// <summary>
		/// 释放一个视频帧。
		/// </summary>
		/// <param name="pFrame">要释放的视频帧对象。</param>
		[DllImport(DllName, SetLastError = true)]
		public static extern void avs_release_video_frame(ref AvsVideoFrame pFrame);
		/// <summary>
		/// 释放一个视频帧。
		/// </summary>
		/// <param name="pFrame">要释放的视频帧对象的指针。</param>
		[DllImport(DllName, SetLastError = true)]
		public static extern void avs_release_video_frame(IntPtr pFrame);

		/// <summary>
		/// 创建一个视频帧的副本。
		/// </summary>
		/// <param name="pFrame">要创建的副本。</param>
		/// <returns>视频帧的副本对象。</returns>
		[DllImport(DllName, SetLastError = true)]
		public static extern IntPtr avs_copy_video_frame(ref AvsVideoFrame pFrame);

		#region 值操作
		/// <summary>
		/// 将一个值对象的内容复制到另一个值对象。
		/// </summary>
		/// <param name="dest">复制的目标。</param>
		/// <param name="src">要复制的内容。</param>
		[DllImport(DllName, SetLastError = true)]
		public static extern void avs_copy_value(ref AvsValue dest, AvsValue src);
		/// <summary>
		/// 释放一个值对象。
		/// </summary>
		/// <param name="value"></param>
		[DllImport(DllName, SetLastError = true)]
		public static extern void avs_release_value(AvsValue value);

		/// <summary>
		/// 获取 AVS 值中的剪辑对象。
		/// </summary>
		/// <param name="value">要获取剪辑的值。</param>
		/// <param name="eEnv">对象所在的环境的指针。</param>
		/// <returns>剪辑对象的指针。</returns>
		[DllImport(DllName, SetLastError = true)]
		public static extern IntPtr avs_take_clip(AvsValue value, IntPtr eEnv);
		/// <summary>
		/// 设置 AVS 值中的剪辑对象。
		/// </summary>
		/// <param name="value">要设置的值。</param>
		/// <param name="pClip">值对应的剪辑对象。</param>
		[DllImport(DllName, SetLastError = true)]
		public static extern void avs_set_to_clip(AvsValue value, IntPtr pClip);

		#endregion

		#region 片段操作

		/// <summary>
		/// 释放一个片段。
		/// </summary>
		/// <param name="pClip">要释放的片段的指针。</param>
		[DllImport(DllName, SetLastError = true)]
		public static extern void avs_release_clip(IntPtr pClip);

		/// <summary>
		/// 复制一个片段。
		/// </summary>
		/// <param name="pClip">要复制的片段的指针。</param>
		/// <returns>新的片段指针。</returns>
		[DllImport(DllName, SetLastError = true)]
		public static extern IntPtr avs_copy_clip(IntPtr pClip);

		/// <summary>
		/// 获取片段的错误信息。
		/// </summary>
		/// <param name="pClip">要获取错误的片段指针。</param>
		/// <returns>片段包含的错误消息，如果没有任何错误，则返回 <c>null</c>。</returns>
		[DllImport(DllName, SetLastError = true, CharSet = CharSet.Ansi)]
		[return: MarshalAs(UnmanagedType.LPStr)]
		public static extern string avs_clip_get_error(IntPtr pClip);
		/// <summary>
		/// 获取片段包含的视频信息。
		/// </summary>
		/// <param name="pClip">要获取视频信息的片段指针。</param>
		/// <returns>该片段对应的视频信息。</returns>
		[DllImport(DllName, SetLastError = true)]
		public static extern IntPtr avs_get_video_info(IntPtr pClip);

		/// <summary>
		/// 获取片段的版本。
		/// </summary>
		/// <param name="pClip">要获取版本的片段指针。</param>
		/// <returns>该片段的版本。</returns>
		[DllImport(DllName, SetLastError = true)]
		public static extern int avs_get_version(IntPtr pClip);

		/// <summary>
		/// 获取片段指定帧的内容。
		/// </summary>
		/// <param name="pClip">要获取帧的片段。</param>
		/// <param name="frameNumber">要获取的帧的编号。</param>
		/// <returns>对应的帧对象。</returns>
		/// <remarks>获取的帧必须使用 <see cref="avs_release_video_frame"/> 释放。</remarks>
		[DllImport(DllName, SetLastError = true)]
		public static extern IntPtr avs_get_frame(IntPtr pClip, int frameNumber);
		/// <summary>
		/// 获取片段指定场的奇偶性。
		/// </summary>
		/// <param name="pClip">要获取奇偶性的片段。</param>
		/// <param name="frameNumber">要获取的场的编号。</param>
		/// <returns>场的奇偶性。</returns>
		/// <remarks>如果片段是基于场的，则返回场的奇偶性，否则返回帧中第一个场的奇偶性。</remarks>
		[DllImport(DllName, SetLastError = true)]
		public static extern int avs_get_parity(IntPtr pClip, int partityNumber);

		/// <summary>
		/// 获取片段中的音频数据。
		/// </summary>
		/// <param name="pClip">要获取音频数据的片段的指针。</param>
		/// <param name="buffer">存放数据的缓冲区。</param>
		/// <param name="start">要获取的第一个音频样本的编号。</param>
		/// <param name="count">要获取的音频样本的数目。</param>
		/// <returns></returns>
		[DllImport(DllName, SetLastError = true)]
		public static extern int avs_get_audio(IntPtr pClip, IntPtr buffer, long start, long count);

		/// <summary>
		/// 设置片段的缓存提示。
		/// </summary>
		/// <param name="pClip"></param>
		/// <param name="cacheHints"></param>
		/// <param name="frameRange"></param>
		/// <returns></returns>
		[DllImport(DllName, SetLastError = true)]
		public static extern int avs_set_cache_hints(IntPtr pClip, int cacheHints, int frameRange);

		#endregion

		/// <summary>
		/// 创建一个新的过滤器。
		/// </summary>
		/// <param name="pEnv">环境的指针。</param>
		/// <param name="fi">过滤器的指针。</param>
		/// <param name="child">过滤器的内部值。</param>
		/// <param name="storeChild">表示是否需要存储剪辑</param>
		/// <returns>剪辑对象的指针。</returns>
		public static extern IntPtr avs_new_c_filter(IntPtr pEnv, ref IntPtr fi, AvsValue child, [MarshalAs(UnmanagedType.Bool)]bool storeChild);


		#region 环境方法

		/// <summary>
		/// 获取系统的 CPU 标志。
		/// </summary>
		/// <param name="pEnv">系统环境的指针。</param>
		/// <returns>系统的 CPU 标志。</returns>
		[DllImport(DllName, SetLastError = true)]
		public static extern CpuFlags avs_get_cpu_flags(IntPtr pEnv);
		/// <summary>
		/// 检查 AVS 环境是否支持指定的版本。
		/// </summary>
		/// <param name="pEnv">系统环境的指针。</param>
		/// <param name="version">要检查的版本。</param>
		/// <returns>如果 AVS 环境支持指定的版本，返回 <c>true</c>；否则返回 <c>false</c>。</returns>
		[DllImport(DllName, SetLastError = true)]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool avs_check_version(IntPtr pEnv, int version);


		//AVSC_API(char *) avs_save_string(AVS_ScriptEnvironment *, const char* s, int length);
		//AVSC_API(char *) avs_sprintf(AVS_ScriptEnvironment *, const char * fmt, ...);

		//AVSC_API(char *) avs_vsprintf(AVS_ScriptEnvironment *, const char * fmt, void* val);
		// // note: val is really a va_list; I hope everyone typedefs va_list to a pointer



		//AVSC_API(int) avs_add_function(AVS_ScriptEnvironment *, 
		//                     const char * name, const char * params, 
		//                     AVS_ApplyFunc apply, void * user_data);

		//AVSC_API(int) avs_function_exists(AVS_ScriptEnvironment *, const char * name);

		//AVSC_API(AVS_Value) avs_invoke(AVS_ScriptEnvironment *, const char * name, 
		//                               AVS_Value args, const char** arg_names);
		//// The returned value must be be released with avs_release_value

		/// <summary>
		/// 获取一个 AVS 变量的值。
		/// </summary>
		/// <param name="pEnv">环境的指针。</param>
		/// <param name="name">要获取的变量的名称。</param>
		/// <returns>变量的值。</returns>
		[DllImport(DllName, SetLastError = true, CharSet = CharSet.Ansi)]
		public static extern AvsValue avs_get_var(IntPtr pEnv, [MarshalAs(UnmanagedType.LPStr)]string name);

		/// <summary>
		/// 设置一个 AVS 变量的值。
		/// </summary>
		/// <param name="pEnv">环境的指针。</param>
		/// <param name="name">要设置的变量的名称。</param>
		/// <param name="value">要设置的变量的值。</param>
		/// <returns>表示操作是否成功的代码。</returns>
		[DllImport(DllName, SetLastError = true, CharSet = CharSet.Ansi)]
		public static extern int avs_set_var(IntPtr pEnv, [MarshalAs(UnmanagedType.LPStr)]string name, AvsValue value);

		/// <summary>
		/// 设置一个 AVS 全局变量的值。
		/// </summary>
		/// <param name="pEnv">环境的指针。</param>
		/// <param name="name">要设置的变量的名称。</param>
		/// <param name="value">要设置的变量的值。</param>
		/// <returns>表示操作是否成功的代码。</returns>
		[DllImport(DllName, SetLastError = true, CharSet = CharSet.Ansi)]
		public static extern int avs_set_global_var(IntPtr pEnv, [MarshalAs(UnmanagedType.LPStr)]string name, AvsValue value);

		/// <summary>
		/// 保存当前上下文。
		/// </summary>
		/// <param name="pEnv">环境的指针。</param>
		/// <param name="level">要保存的层数。</param>
		[DllImport(DllName, SetLastError = true)]
		public extern static void avs_push_context(IntPtr pEnv, int level);

		/// <summary>
		/// 恢复当前上下文。
		/// </summary>
		/// <param name="pEnv">环境的指针。</param>
		[DllImport(DllName, SetLastError = true)]
		public extern static void avs_pop_context(IntPtr pEnv);

		/// <summary>
		/// 注册 AVS 环境退出函数。
		/// </summary>
		[DllImport(DllName, SetLastError = true)]
		public extern static void avs_at_exit(IntPtr pEnv, AvsShutDownFunc callback, IntPtr userData);

		//AVSC_API(AVS_VideoFrame *) avs_new_video_frame_a(AVS_ScriptEnvironment *, 
		//                                          const AVS_VideoInfo * vi, int align);


		//        AVSC_API(int) avs_make_writable(AVS_ScriptEnvironment *, AVS_VideoFrame * * pvf);

		//AVSC_API(void) avs_bit_blt(AVS_ScriptEnvironment *, BYTE* dstp, int dst_pitch, const BYTE* srcp, int src_pitch, int row_size, int height);

		//AVSC_API(AVS_VideoFrame *) avs_subframe(AVS_ScriptEnvironment *, AVS_VideoFrame * src, int rel_offset, int new_pitch, int new_row_size, int new_height);
		//// The returned video frame must be be released


		/// <summary>
		/// 设置环境允许使用的最大内存值。
		/// </summary>
		/// <param name="pEnv">环境的指针。</param>
		/// <param name="newDir">最大内存值，以字节为单位。</param>
		/// <returns>表示操作是否成功的代码。</returns>
		[DllImport(DllName, SetLastError = true, CharSet = CharSet.Ansi)]
		public static extern int avs_set_memory_max(IntPtr pEnv, int mem);

		/// <summary>
		/// 设置新的工作目录。
		/// </summary>
		/// <param name="pEnv">环境的指针。</param>
		/// <param name="newDir">新的工作目录。</param>
		/// <returns>表示操作是否成功的代码。</returns>
		[DllImport(DllName, SetLastError = true, CharSet = CharSet.Ansi)]
		public static extern int avs_set_working_dir(IntPtr pEnv, [MarshalAs(UnmanagedType.LPStr)]string newDir);

		/// <summary>
		/// 创建一个指定版本的 AVS 环境。
		/// </summary>
		/// <param name="version">要创建的 AVS 环境的版本。</param>
		/// <returns>指定版本的 AVS 环境。如果创建环境失败，则返回 <see cref="IntPtr.Zero"/>。</returns>
		[DllImport(DllName, SetLastError = true)]
		public static extern IntPtr avs_create_script_environment(int version);

		/// <summary>
		/// 删除指定的 AVS 环境。
		/// </summary>
		/// <param name="pEnv">要删除的环境的指针。</param>
		[DllImport(DllName, SetLastError = true)]
		public static extern void avs_delete_script_environment(IntPtr pEnv);


		//AVSC_API(AVS_VideoFrame *) avs_subframe_planar(AVS_ScriptEnvironment *, AVS_VideoFrame * src, int rel_offset, int new_pitch, int new_row_size, int new_height, int rel_offsetU, int rel_offsetV, int new_pitchUV);

		#endregion

	}
}
